package com.itheima.utils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ResourceBundle;

/**
 * Bean 对象 Factory 工厂 Utils 工具类
 *  负责程序中的对象创建
 */
public class BeanFactoryUtils {
    /**
     * 问题:  类过多 if else就太多了->>> 抽
     * 1.在配置文件中声明 key和全限定类名的关系
     * 2.外部传入标识符
     * 3.方法的内部 根据标识符 找到对应的全限定类名
     * 4.实例化对象返回即可
     */
    public static Object getBean(String key){//外部传入的 routeService , categoryService
        Object o = null;
        Object proxy =null;
        try {
            //1.加载配置文件 只能读取properties格式配置文件
            ResourceBundle bundle = ResourceBundle.getBundle("bean");
            //2.根据key获得全限定类名
            String className = bundle.getString(key);
            //3.反射实例化对象
            o = Class.forName(className).newInstance();
            //4.创建代理对象，对原有功能增强（记录日志信息）
            /**
             * 参数一：类加载器  当前类.class.getClassLoader();
             * 参数二：被代理对象实现的接口数组   被代理对象.getClass().getInterfaces()
             * 参数三：处理器执行器  作用：对被代理对象中的方法（功能）进行增强
             */
            Object finalO = o;
            proxy = Proxy.newProxyInstance(BeanFactoryUtils.class.getClassLoader(), o.getClass().getInterfaces(), new InvocationHandler() {
                /**
                 *   代理对象增强的方法
                 * @param proxy   代理对象
                 * @param method  被代理对象中的方法
                 * @param args  被代理对象中的方法参数列表
                 * @return
                 * @throws Throwable
                 */
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                    System.out.println(className + "中的方法" + method.getName() + "开始执行时间：" + System.currentTimeMillis());
                    //执行原有方法
                    Object result = method.invoke(finalO, args);
                    System.out.println(className + "中的方法" + method.getName() + "结束执行时间：" + System.currentTimeMillis());
                    return result;
                }
            });

        } catch (Exception e) {
            e.printStackTrace();
        }
        return proxy;
    }
}
